package com.google.code.pokerstats_service.math;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.google.code.pokerstats_service.Game;
import com.google.code.pokerstats_service.PlayerResult;
import com.google.code.pokerstats_service.PlayerStats;

/**
 * Calculates players' player-group weighted expectations and stats.
 * @author DL
 */
public class GroupExpectationCalculator {

    public void updateStats(
	    Map<Game, Set<PlayerResult>> games, Map<Long, PlayerStats> playersStats) {
	
        // Map player groups to games
        Map<Set<Long>, Map<Game, Set<PlayerResult>>> playerGroupToGamesMap =
            new HashMap<Set<Long>, Map<Game, Set<PlayerResult>>>();
        
        for (Game game : games.keySet()) {
            Set<Long> playerGroup = new HashSet<Long>();
            for (PlayerResult playerResult : games.get(game)) {
                playerGroup.add(playerResult.player);
            }
            
            Map<Game, Set<PlayerResult>> gamesByPlayerGroup =
        	    playerGroupToGamesMap.get(playerGroup);
            if (gamesByPlayerGroup == null) {
                gamesByPlayerGroup = new HashMap<Game, Set<PlayerResult>>();
                playerGroupToGamesMap.put(playerGroup, gamesByPlayerGroup);
            }
            gamesByPlayerGroup.put(game, games.get(game));
        }
        
        // Calculate temporary stats for each (player group, player) pair
        Map<Set<Long>, Map<Long, PlayerStats>> playerGroupToTempStats =
            new HashMap<Set<Long>, Map<Long, PlayerStats>>();
        
        for (Set<Long> playerGroup : playerGroupToGamesMap.keySet()) {
            Map<Long, PlayerStats> tempStats = new HashMap<Long, PlayerStats>();
            for (Long playerId : playerGroup) {
                tempStats.put(playerId, new PlayerStats(playerId));
            }
            
            basicStatsCalculator.updateStats(
                playerGroupToGamesMap.get(playerGroup), tempStats);
            playerGroupToTempStats.put(playerGroup, tempStats);
        }
        
        // Calculate weighted expectations
        Map<Long, Integer> playerToNumPlayerGroups = new HashMap<Long, Integer>();
        for (Long fbUid : playersStats.keySet()) {
            playersStats.get(fbUid).groupPlayed = 0;
            playersStats.get(fbUid).groupExpectation = 0.0;
            
            playerToNumPlayerGroups.put(fbUid, 0);
        }
        
        for (Set<Long> playerGroup : playerGroupToTempStats.keySet()) {
            Map<Long, PlayerStats> tempStats = playerGroupToTempStats.get(playerGroup);
            for (Long fbUid : tempStats.keySet()) {
                int tmp = playerToNumPlayerGroups.get(fbUid);
                playerToNumPlayerGroups.put(fbUid, tmp + 1);
                
                PlayerStats stats = playersStats.get(fbUid);
                stats.groupExpectation += tempStats.get(fbUid).expectation;
            }
        }
        
        // Normalize weighted expectations
        for (PlayerStats stats : playersStats.values()) {
            int numPlayerGroups = playerToNumPlayerGroups.get(stats.fbUid);
            if (numPlayerGroups > 0) {
                stats.groupExpectation /= numPlayerGroups;
                stats.groupPlayed = numPlayerGroups;
            }
        }
    }
    
    private BasicStatsCalculator basicStatsCalculator = new BasicStatsCalculator();
}